I defined two Relationship(Orderable, models.Model) to be able to use one modelsnippet inside differen Page models like:
class GroupstageTournamentModel(models.Model):
...
class GroupstageTournamentRelationship(Orderable, models.Model):
page = ParentalKey('TournamentPage',
related_name='groupstage_tournament_relationship')
match = models.ForeignKey('GroupstageTournamentModel',
related_name='match_tournament_relationship')
panels = [
PageChooserPanel('match')
]
class MatchesScreencastRelationship(Orderable, models.Model):
page = ParentalKey('ScreencastPage',
related_name='groupstage_screencast_relationship')
match = models.ForeignKey('GroupstageTournamentModel',
default="", related_name='match_screen_relationship')
panels = [
PageChooserPanel('match')
]
class TournamentPage(Page):
starts_at = models.DateTimeField(blank=True)
ends_at = models.DateTimeField(blank=True)
content_panels = Page.content_panels + [
FieldPanel('title'),
FieldPanel('starts_at'),
FieldPanel('ends_at'),
InlinePanel(
'groupstage_tournament_relationship', label="Group game:",
panels=None, min_num=1),
]
def __str__(self):
return self.title
class ScreencastPage(Page):
content_panels = Page.content_panels + [
FieldPanel('title'),
InlinePanel(
'groupstage_screencast_relationship', label="Playing First",
panels=None, max_num=1),
]
parent_page_types = ['home.HomePage']
subpage_types = []
def __str__(self):
# return self.title
return '{} \n Nächste: {}'.format(self.groupstage_relationship, self.final_phase_relationship)
As you can see my idea was to use one of them insite TournamentPage and another inside ScreencastPage. If i do that this way i get this error:
ERROR:
django.core.exceptions.FieldError: Local field 'id' in class 'GroupstageTournamentRelationship' clashes with field of the same name from base class 'GroupstageTournamentModel'.
how can this problem be solved? Is it possible to add somehow the second ParentalKey for relationship with ScreencastPage and use it direct inside GroupstageTournamentModel like you did in backerydemo?
UPDATE
I changed GroupstageTournamentModel from model.Model to ClusterableModel and i changed related_name so that it different in both of related_name's
related_name='groupstage_tournament_relationship' and related_name='groupstage_screencast_relationship'. I did migrations again and got the same error. Here is my GroupstageTournamentRelationship class:
class GroupstageTournamentModel(ClusterableModel):
number = models.PositiveSmallIntegerField(
help_text="Add the unique number of this Match.")
starts_at = models.DateTimeField()
# Team 1
team_1 = models.ForeignKey(
TeamRooster,
null=True, blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
team_1_dress = ColorField(default='#ff0000', blank=True)
team_1_first_halftime_score = models.PositiveSmallIntegerField(blank=True, default="")
# Team 2
team_2 = models.ForeignKey(
TeamRooster,
null=True, blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
team_2_dress = ColorField(default='#0066ff', blank=True)
team_2_first_halftime_score = models.PositiveSmallIntegerField(blank=True, default="")
panels = [
FieldPanel('number', classname="6"),
FieldPanel('starts_at', classname="6"),
MultiFieldPanel([
FieldRowPanel([
FieldPanel('team_1', classname="6"),
FieldPanel('team_1_dress', classname="6"),
FieldPanel('team_1_first_halftime_score', classname="3"),
]),
], classname="full", heading="Team 1"),
MultiFieldPanel([
FieldRowPanel([
FieldPanel('team_2', classname="6"),
FieldPanel('team_2_dress', classname="6"),
FieldPanel('team_2_first_halftime_score', classname="3"),
]),
], classname="full", heading="Team 2"),
]
def __str__(self):
return '{} vs {} {} - {}'.format(self.team_1, self.team_2, self.starts_at, self.number)
class Meta:
verbose_name = 'Gruppenphase Spiel'
verbose_name_plural = 'Gruppenphase'
UPDATE
In migration file i found following, and Im not sure what happens if I remove that:
UPDATE
I shortened the model and added "TournamentPage" for clarity.
I deleted my migration files included 0001_inicial.py and did again py manage.py makemigrations and it all worked !
Related
wagtail 4.1 It seems that I did everything as stated in the documentation, but my models do not appear in the admin panel.path
my model:
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
cover_photo = models.ForeignKey(
'wagtailimages.Image',
null=True, blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
panels = [
FieldPanel('title'),
FieldPanel('author'),
FieldPanel('cover_photo')
]
my wagtail_hooks.py
class BookAdmin(ModelAdmin):
model = Book
menu_label = 'Book' # ditch this to use verbose_name_plural from model
menu_icon = 'pilcrow' # change as required
menu_order = 201 # will put in 3rd place (000 being 1st, 100 2nd)
add_to_settings_menu = True # or True to add your model to the Settings sub-menu
exclude_from_explorer = True # or True to exclude pages of this type from Wagtail's explorer view
list_display = ('title', 'author')
list_filter = ('author',)
search_fields = ('title', 'author')
# Now you just need to register your customised ModelAdmin class with Wagtail
modeladmin_register(BookAdmin)
I also registered my applications
INSTALLED_APPS = [
...
"news",
"app",
"wagtail.contrib.modeladmin",
]
what can i miss?
I am working on a post request in which the user chooses from a list of tags and makes combinations of tags. The combination of tags should then be posted. Nothing should get changed in the Tag table.
These are the models:
models.py
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
"""Return a human readable representation of the model instance."""
return self.name or ''
#property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Combination(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, null=True)
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, null=True)
tag_id = models.ManyToManyField(Tag, null=True)
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
objects = models.Manager()
def __str__(self):
return str(self.tag_id) or ''
This is the serializer for Combination.
serializers.py
class CombinationSerializer(serializers.ModelSerializer):
tag_id = TagWithIdSerializer(many=True, required=False, write_only=False)
resource_id = serializers.PrimaryKeyRelatedField(queryset=Resource.objects.all(),
required=True,
source='resource',
write_only=False)
gameround_id = serializers.PrimaryKeyRelatedField(queryset=Gameround.objects.all(),
required=False,
source='gameround',
write_only=False)
user_id = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all(),
required=False,
source='user',
write_only=False)
class Meta:
model = Combination
depth = 1
fields = ('id', 'user_id', 'gameround_id', 'resource_id', 'tag_id', 'created', 'score')
def create(self, validated_data):
user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
score = 0
tag_data = validated_data.pop('tag_id', None)
combination = Combination(
user=user,
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
created=datetime.now(),
score=score
)
combination.save()
for tag_object in tag_data[0]:
combination.tag_id.add(tag_object)
return combination
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['tag_id'] = TagWithIdSerializer(instance.tag_id.all(), many=True).data
return rep
I have tried posting the following JSON object to the database:
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [{"id": 2014077506, "name": "corwn","language": "en"}]
}
I am getting a ValueError: Field 'id' expected a number but got 'name'.
How can I fix this issue?
you need to provide tag id for each tag not all tag data,
Try like this
{
"gameround_id": 2015685170,
"resource_id": 327888,
"tag_id": [2014077506,2014077507]
}
I have an Annonce page with this model:
class AnnoncePage(Page):
date = models.DateField("Date de publication", blank=True, null=True)
description = RichTextField(features=['h2', 'h3', 'bold', 'italic', 'link', 'hr', 'ol', 'ul'], blank=True)
lieu = models.CharField(blank=True, max_length=200)
surface = models.PositiveSmallIntegerField(blank=True, null=True)
nb_pieces = models.PositiveSmallIntegerField(blank=True, null=True)
prix_affiché_index = models.CharField(blank=True, max_length=200, null=True)
conditions_vente_et_prix = RichTextField(blank=True, features=['h2', 'h3', 'bold', 'italic', 'link', 'hr', 'ol', 'ul'])
def main_image(self):
gallery_item = self.gallery_images.first()
if gallery_item:
return gallery_item.image
else:
return None
content_panels = Page.content_panels + [
FieldPanel('date'),
InlinePanel('gallery_images', label="Gallery images"),
FieldPanel('lieu', classname="full"),
FieldPanel('surface', classname="full"),
FieldPanel('nb_pieces', classname="full"),
FieldPanel('description', classname="full"),
FieldPanel('prix_affiché_index', classname="full"),
FieldPanel('conditions_vente_et_prix', classname="full")
]
promote_panels = []
settings_panels = []
max_count = 20
class AnnoncePageGalleryImage(Orderable):
page = ParentalKey(AnnoncePage, on_delete=models.SET_NULL, related_name='gallery_images', null=True)
image = models.ForeignKey(
'wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True
)
panels = [
ImageChooserPanel('image')
]
How can I automaticaly delete the images of the Annonce page after deleting the Annonce page itself ? Do I need to change the model ?
The Wagtail image object can be used in other places. Deleting those automagically might have nasty side effects for other content.
You can add a delete method to AnnoncePage or use a pre_delete signal. You need to iterate over all related gallery images and delete the related Wagtail images. Django leaves the file on disk, so you might want to handle that too.
class AnnoncePage(Page):
...
def delete(self):
for gallery_image in self.gallery_images.all():
# Delete the file on disk here ...
# After, delete the db obj.
gallery_image.image.all().delete()
self.gallery_images.all().delete()
super().delete()
Disclaimer: untested code.
https://docs.djangoproject.com/en/dev/topics/db/models/#overriding-model-methods
https://docs.djangoproject.com/en/dev/ref/signals/#pre-delete
https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.fields.files.FieldFile.delete
Note that the delete method and pre_delete signal are not called on bulk actions. Your milage may vary.
I have this Page model:
class BlogPostPage(Page):
date_published= models.DateField('Published date', blank=True, null=True)
intro= models.CharField(max_length=250)
body = RichTextField(blank=True)
header_image = models.ForeignKey('wagtailimages.Image', blank=True, null=True,
on_delete=models.SET_NULL, related_name='+')
tags = ClusterTaggableManager(through='blog.BlogPageTag', blank=True)
categories = ParentalManyToManyField('blog.BlogCategory', blank=True)
def get_context(self, request):
context = super().get_context(request)
all_categories = []
for post in self.get_siblings(inclusive=True):
all_categories +=post.specific.categories.all()
all_categories = sorted(set(all_categories))
context['all_categories']= all_categories
return context
When the page is access I get a TypeError:
TypeError at /blog/xxx/
'<' not supported between instances of 'BlogCategory' and 'BlogCategory'
Inputs on why this is happening and how it can be avoided are requested.
You can define the key parameter for sorted, according to key functions.
But I am not sure, is + allowed in: all_categories +=post.specific.categories.all()?
I struggle to implement something like "nested categories":
PageA:
- Cat1
- SubCat1
- SubCat2
- ...
- Cat2
- SubCat1
- ...
All categories and subcategories should be orderable and editable by an editor.
My guess was something like this:
class CategoryTestPage(Page):
content_panels = Page.content_panels + [
InlinePanel('categories')
]
class Category(Orderable,ClusterableModel,models.Model):
page = ParentalKey(CategoryTestPage, related_name='category')
category = models.CharField(max_length=250)
def __str__(self):
return "%d %s" % (self.id, self.category)
panels = [
FieldPanel('category'),
InlinePanel('subcategory')
]
class SubCategory(Orderable,models.Model):
category = ParentalKey(ProjektOrdnung, related_name='subcategory')
subcategory = models.CharField(max_length=250)
def __str__(self):
return "%d %s" % (self.id, self.subcategory)
panels = [
FieldPanel('subcategory')
]
But this results in 'CategoryForm' object has no attribute 'formsets'. It seems nested InlinePanels are the problem?
Further I need this "hierarchical taxonomy" for assigning some of these categories/subcategories to other pages:
PageB:
- has Cat1
- has SubCa2
- ...
... which looks a lot like hierarchical tags...
Any ideas how to implement this or what's wrong with my implementation?
Kind regards,
tombreit
PS: I'm on wagtail 1.2rc1
Here's one way to do it, with much room for interface improvements ;) In order to sort the categories at the page level, I'd suggest the use of django-sortedm2m.
from wagtail.wagtailcore.models import Orderable, Page
from wagtail.wagtailsnippets.models import register_snippet
from django.db import models
#register_snippet
class Category(models.Model):
name = models.CharField(
max_length=80, unique=True, verbose_name=_('Category Name'))
slug = models.SlugField(unique=True, max_length=80)
parent = models.ForeignKey(
'self', blank=True, null=True, related_name="children",
help_text=_(
'Categories, unlike tags, can have a hierarchy. You might have a '
'Jazz category, and under that have children categories for Bebop'
' and Big Band. Totally optional.')
)
description = models.CharField(max_length=500, blank=True)
class Meta:
ordering = ['name']
verbose_name = _("Category")
verbose_name_plural = _("Categories")
panels = [
FieldPanel('name'),
FieldPanel('parent'),
FieldPanel('description'),
]
def __str__(self):
return self.name
def clean(self):
if self.parent:
parent = self.parent
if self.parent == self:
raise ValidationError('Parent category cannot be self.')
if parent.parent and parent.parent == self:
raise ValidationError('Cannot have circular Parents.')
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
return super(Category, self).save(*args, **kwargs)
class CategoryPage(models.Model):
category = ParentalKey('Category', related_name="+", verbose_name=_('Category'))
page = ParentalKey('MyPage', related_name='+')
panels = [
FieldPanel('category'),
]
class MyPage(Page):
categories = models.ManyToManyField(Category, through=CategoryPage, blank=True)
content_panels = Page.content_panels + [
FieldPanel('categories'),
]