Wagtail | ChoiceField not displayed - python

I am facing some kind of incomprehensible behavior working with "StructBlock" and "ChoiceBlock". For some reasons the ChoiceBlock dont show up in admin-menu if designed via class-notation.
Like that no choiceblock is shown at admin-menu. Only the textblock.
class CodeBlock(blocks.StructBlock):
code = blocks.TextBlock(required=True)
type = blocks.ChoiceBlock(choices=[
('markup', 'markup'), ('css', 'css')
], required=True),
class Meta:
template = 'home/blocks/code.html'
class HomePageIndex(Page):
body = StreamField([('code', CodeBlock())])
content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]
The following solution is in my opinion pretty much equal, but works well. I do not get why... Due the fact i need the Struct-Field more often i prefer the the class-notation.
class HomePageIndex(Page):
body = StreamField([
('code', blocks.StructBlock([
('code', blocks.TextBlock(required=True)),
('type', blocks.ChoiceBlock(choices=[
('markup', 'markup'), ('css', 'css')
], template='home/blocks/code.html'))
])
content_panels = Page.content_panels + [
StreamFieldPanel('body'),
Not get me wrong, i could make it work (using the bad-way). I wonder why that happens.
Ty in advance

Related

Value Error: Field 'id' expected a number but got 'create'

I was in the process of making a create gallery image field in Django for my project, but when I try to access the url, I'm getting a Field 'id' expected a number but got 'create'. error. And on postman, I'm getting a { detail: "Method \"POST\" not allowed." }.
class Gallery(models.Model):
SUBTLEPBR = "subtle"
AMULET = "amulet"
F8THFULPBR = "f8thfulpbr"
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
screenshot_by = models.CharField(max_length=200, null=False, blank=False)
image = WEBPField(
verbose_name=('Image'),
upload_to=image_folder,
default="placeholder.png"
)
PACKS = [
(SUBTLEPBR, 'SubtlePBR'),
(AMULET, 'Amulet'),
(F8THFULPBR, 'F8thfulPBR'),
]
pack = models.CharField(max_length=10, choices=PACKS)
def __str__(self):
return "Screenshot by "+ self.screenshot_by + " | " + self.pack
#api_view(["POST"])
#permission_classes([IsAdminUser])
def createGalleryImage(request):
user = request.user
gallery = Gallery.objects.create(
user = user,
screenshot_by = "John Doe",
pack = Gallery.SUBTLEPBR,
)
serializer = GallerySerializer(gallery, many=False)
return Response(serializer.data)
urlpatterns = [
path('admin/users/login/', views.MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('', views.getRoutes, name='routes'),
path("gallery/", views.GalleryImages, name="gallery"),
path("gallery/<str:pk>/", views.getGalleryImage, name="gallery-image"),
path("gallery/delete/<str:pk>/", views.deleteGalleryImage, name="gallery-delete"),
path("gallery/create/", views.createGalleryImage, name="gallery-create"),
path("updates/", views.PackUpdatesPage, name="updates"),
path("faq/", views.FaqPage, name="faq"),
path("subtle-roadmap/", views.SubtleRoadmapPage, name="subtle-roadmap"),
path("amulet-roadmap/", views.AmuletRoadmapPage, name="amulet-roadmap"),
path('admin/users/profile/', views.getUserProfile, name="user-profile")
]
The output that is supposed to happen is
{
"id": 51,
"screenshot_by": "Person",
"image": "/placeholder.png",
"pack": "subtle",
"user": 1
}
(added entire urls code to include entirety of paths)
This will "fire" the wrong view. Indeed, if you use /gallery/create, it will fire getGalleryImage with create as pk.
If the primary keys are integers, you can restrict these with:
urlpatterns = [
path('gallery/<int:pk>/', views.getGalleryImage, name='gallery-image'),
path(
'gallery/delete/<int:pk>/',
views.deleteGalleryImage,
name='gallery-delete',
),
path('gallery/create/', views.createGalleryImage, name='gallery-create'),
# …
]
This will then only "fire" if pk is a sequence of digits, like 1425, not create.

Using django modeling, how do you properly extend a model?

I'm an amateur developer who has been learning python in order to build my first full-stack project, which is an animal exchange site for a game I play. The animals can have up to 3 traits, but some of them have special ones. In the case of animals with special traits, I attempted to extend the base model and add additional traits using a notation someone suggested, but it doesn't seem to work. I know that technically I can just copypaste the base trait set and manually add them in, with a different model every time but that seems like it would bloat my code, and I'd like to be efficient about it. If you notice something else that could be improved, please let me know, thanks.
from django.db import models
#traits listed in class animal are base traits
class ANIMAL(models.Model):
MALE = 'MA'
FEMALE = 'FE'
SHINY = 'SHI'
NORMAL = 'NOR'
EGG = 'EGG'
CHILD = 'CHI'
ADOLESCENT = 'ADO'
ADULT = 'ADU'
ELDER = 'ELD'
BIGBONED = 'BIGB'
BUTTERFACE = 'BUTT'
CHARMED = 'CHAR'
CHATTY = 'CHAT'
CONSTIPATED = 'CONS'
CURVY = 'CURV'
EVIL = 'EVIL'
EXALTED = 'EXAL'
FORTUNATE = 'FORT'
FREAKOFNATURE = 'FREA'
FROSTBREATH = 'FROS'
FUSSYEATER = 'FUSS'
GENETICINFERIORITY = 'GINF'
GENETICINSTABILITY = 'GINS'
GENETICMUTATION = 'GENM'
GENIUS = 'GENI'
GIVER = 'GIVE'
GLISTENING = 'GLIS'
GOLDENGIFT = 'GOLD'
GOOD = 'GOOD'
GOODBREEDING = 'GOOB'
HANDSOME = 'HAND'
HYPERACTIVE = 'HYPE'
IMMUNE = 'IMMU'
INSANE = 'INSA'
JOVIAL = 'JOVI'
JOYFUL = 'JOYF'
LIMITEDEFFICIENCY = 'LIMI'
LITHE = 'LITH'
LUCKY = 'LUCK'
MYSTERIOUS = 'MYST'
NICEBUTDIM = 'NICE'
OLDATHEART = 'OLDA'
PERFECTED = 'PERF'
PLAIN = 'PLAI'
POISONOUSBREATH = 'POIS'
PRIZESPECIMAN = 'PRIZ'
PRODUCER = 'PROD'
RADIANT = 'RADI'
RAVENSWORN = 'RAVE'
REGULAR = 'REGU'
ROBUST = 'ROBU'
SHOCKBREATH = 'SHOC'
SICKLY = 'SICK'
SLOWPOKE = 'SLOW'
SMELLY = 'SMEL'
SPARKLING = 'SPAR'
STINGY = 'STIN'
STRESSED = 'STRE'
STRONGGENES = 'STRO'
STUDLY = 'STUD'
SULLEN= 'SULL'
SURLY = 'SURL'
TAKER = 'TAKE'
UNLUCKYFORSOME = 'UNLU'
VIRILE = 'VIRI'
YOUNGATHEART = 'YOUN'
NONE = 'NONE'
GENDER_CHOICES = [
(MALE, 'Male'),
(FEMALE, 'Female'),
]
AGE_CHOICES = [
(EGG, 'Egg'),
(CHILD, 'Child'),
(ADOLESCENT, 'Adolescent'),
(ADULT, 'Adult'),
(ELDER, 'Elder'),
]
SHINY_CHOICES = [
(SHINY, 'Shiny'),
(NORMAL, 'Normal'),
]
FIRST_TRAIT_CHOICES = [
(BIGBONED, 'Big Boned'),
(CONSTIPATED, 'Constipated'),
(FUSSYEATER, 'Fussy Eater'),
(GENETICINFERIORITY, 'Genetic Inferiority'),
(GENETICMUTATION, 'Genetic Mutation'),
(GIVER, 'Giver'),
(HANDSOME, 'Handsome'),
(HYPERACTIVE, 'Hyperactive'),
(JOVIAL, 'Jovial'),
(JOYFUL, 'Joyful'),
(LUCKY, 'Lucky'),
(OLDATHEART, 'Old at Heart'),
(PLAIN, 'Plain'),
(PRODUCER, 'Producer'),
(REGULAR, 'Regular'),
(ROBUST, 'Robust'),
(SICKLY, 'Sickly'),
(SLOWPOKE, 'Slowpoke'),
(SPARKLING, 'Sparkling'),
(STINGY, 'Stingy'),
(STRESSED, 'Stressed'),
(STUDLY, 'Studly'),
(SULLEN, 'Sullen'),
(SURLY, 'Surly'),
(VIRILE, 'Virile'),
(YOUNGATHEART, 'Young at Heart'),
]
SECOND_TRAIT_CHOICES = [
(NONE, 'None'),
(CHARMED, 'Charmed'),
(CHATTY, 'Chatty'),
(EVIL, 'Evil'),
(GENETICINSTABILITY, 'Genetic Instability'),
(GENETICMUTATION, 'Genetic Mutation'),
(GENIUS, 'Genius'),
(GIVER, 'Giver'),
(GLISTENING, 'Glistening'),
(GOOD, 'Good'),
(GOODBREEDING, 'Good Breeding'),
(HANDSOME, 'Handsome'),
(HYPERACTIVE, 'Hyperactive'),
(IMMUNE, 'Immune'),
(INSANE, 'Insane'),
(JOVIAL, 'Jovial'),
(JOYFUL, 'Joyful'),
(LUCKY, 'Lucky'),
(MYSTERIOUS, 'Mysterious'),
(PERFECTED, 'Perfected'),
(PRODUCER, 'Producer'),
(RAVENSWORN, 'Ravensworn'),
(ROBUST, 'Robust'),
(SMELLY, 'Smelly'),
(SPARKLING, 'Sparkling'),
(STRONGGENES, 'Strong Genes'),
(STUDLY, 'Studly'),
(VIRILE, 'Virile'),
]
THIRD_TRAIT_CHOICES = [
(NONE, 'None'),
(BUTTERFACE, 'Butterface'),
(CHARMED, 'Charmed'),
(CURVY, 'Curvy'),
(EXALTED, 'Exalted'),
(FORTUNATE, 'Fortunate'),
(FREAKOFNATURE, 'Freak of Nature'),
(GENETICINSTABILITY, 'Genetic Instability'),
(GENETICMUTATION, 'Genetic Mutation'),
(GIVER, 'Giver'),
(GLISTENING, 'Glistening'),
(GOLDENGIFT, 'Golden Gift'),
(GOODBREEDING, 'Good Breeding'),
(IMMUNE, 'Immune'),
(JOYFUL, 'Joyful'),
(LIMITEDEFFICIENCY, 'Limited Efficiency'),
(LITHE, 'Lithe'),
(LUCKY, 'Lucky'),
(MYSTERIOUS, 'Mysterious'),
(NICEBUTDIM, 'Nice But Dim'),
(PERFECTED, 'Perfected'),
(PRIZESPECIMAN, 'Prize Speciman'),
(PRODUCER, 'Producer'),
(RADIANT, 'Radiant'),
(SPARKLING, 'Sparkling'),
(STRONGGENES, 'Strong Genes'),
(STUDLY, 'Studly'),
(UNLUCKYFORSOME, 'Unlucky For Some'),
]
# max_length refers to the length of the characters stored in the database, not the length of the trait
gender_of_animal = models.CharField(
max_length= 6,
choices= GENDER_CHOICES,
default=MALE,
)
shiny_or_not = models.CharField(
max_length=3,
choices=SHINY_CHOICES,
default=NORMAL,
)
age_of_animal = models.CharField(
max_length=3,
choices=AGE_CHOICES,
default=ADOLESCENT,
)
first_trait = models.CharField(
max_length=4,
choices=FIRST_TRAIT_CHOICES,
default=SPARKLING,
)
second_trait = models.CharField(
max_length=4,
choices=SECOND_TRAIT_CHOICES,
default=NONE,
)
third_trait = models.CharField(
max_length=4,
choices=THIRD_TRAIT_CHOICES,
default=NONE,
)
#class Meta:
# abstract = True
class DRAGON(ANIMAL):
FIRST_TRAIT_CHOICES + ((FROSTBREATH, 'Frost Breath'), (POISONOUSBREATH, 'Poisonous Breath'), (SHOCKBREATH, 'Shock Breath',))
SECOND_TRAIT_CHOICES += ((FROSTBREATH, 'Frost Breath'), (POISONOUSBREATH, 'Poisonous Breath'), (SHOCKBREATH, 'Shock Breath',))
THIRD_TRAIT_CHOICES += ((FROSTBREATH, 'Frost Breath'), (POISONOUSBREATH, 'Poisonous Breath'), (SHOCKBREATH, 'Shock Breath',))
This is okay if you want your dragons to be separate from other animals, but I get the feeling you might not want this. Say you want to get all animals, you couldn't just do Animal.objects.all(), you would have to do Dragon.objects.all(), ... etc. for each one.
I would recommend the following restructuring:
Move all of your choices into separate models, there are just way too many in my opinion and they are both repetitive and hardcoded.
# Instead of
FIRST_TRAIT_CHOICES = [
(BIGBONED, 'Big Boned'),
... etc.
# do
class Trait(models.Model):
name = models.CharField(...
animal_types = models.ManyToManyField(...
# ^ m2m as many animals can have many trains
Note the animal_types field above - create another model that captures the type of animal, e.g. a Dragon:
class AnimalType(models.Model):
name = models.CharField(... # e.g. Dragon, etc.
Then attach this to your animal model - you can also do this for you traits. It makes it far more manageable and dynamic, also removing a lot of bloat from your model code.
class Animal(models.Model):
animal_type = models.ForeignKey(AnimalType, ...
first_trait = models.ForeignKey(Trait, ...
... etc.
Going back to your traits, you can create logic to ensure only certain animal types can have certain traits.
This makes your code much cleaner, you're pushing all of the data into the database which makes it more easily editable. It also means that if ever the traits or animal types change then you don't have to bulk update charfields, you just change the database entry.
Finally, you can get all dragons like this, without removing the ability to have dragons and other animals together in a queryset:
dragons = Animal.objects.filter(animal_type__name="dragon")

Wagtail admin ,CheckboxSelectMultiple not saving data

#register_snippet
class Numbers(models.Model):
number = models.IntegerField()
class State(models.Model):
state = models.CharField(max_length=100)
number = ParentalManyToManyField(Numbers)
class HomeStateNumber(State):
page = ParentalKey('home.HomePage', related_name='helpline')
api_fields = ['state', 'number']
panels = [
FieldPanel('state'),
FieldPanel('number',widget=forms.CheckboxSelectMultiple),
]
class HomePage(Page):
content_panels = [
FieldPanel('title'),
ImageChooserPanel('cover_page'),
InlinePanel('ticker', label="ticker"),
InlinePanel('helpline', label="helpline"),
]
I want to add one than more number in a state , wagtail shows correct order in admin , when you select number from multiple and save the page, data is not saved. It remains None (queryset)
Is there any other way to do this ?
I think i am doing wrong somewhere
Please help
Models using ParentalManyToManyField need to inherit from modelcluster.models.ClusterableModel.
from modelcluster.models import ClusterableModel
class State(ClusterableModel):
state = models.CharField(max_length=100)
number = ParentalManyToManyField(Numbers)
Also, make sure you have django-modelcluster version 4.0 (or above) installed - older versions had a bug preventing m2m relations in inline objects from working.

How can I add a document on a StreamField in Wagtail CMS?

I've a question about Wagtail CMS.
Recently I'm trying to import programmatically some documents in a StreamField of an instance of a Wagtail Page model. I've done some researches but without results.
Currently I'm using:
Wagtail 1.13
Django 1.11.6
Python 2.7
Here the model of the page in which I need to import the documents as attachments (see the homonym field):
class EventPage(TranslatablePage, Page):
# Database fields
uuid = models.UUIDField(verbose_name='UUID', default=uuid.uuid4)
start_date = models.DateField(verbose_name='Start date')
end_date = models.DateField(verbose_name='End date')
location = models.CharField(verbose_name='Place', max_length=255, null=True, blank=True)
body = RichTextField(verbose_name='Body')
attachments = StreamField(blocks.StreamBlock([
('document', DocumentChooserBlock(label='Document', icon='doc-full-inverse')),
]), verbose_name='Attachments', null=True, blank=True)
subscribe = models.BooleanField(verbose_name='Subscribe option', default=False)
# Editor panels configuration
content_panels = [
FieldPanel('title', classname='title'),
MultiFieldPanel([
FieldRowPanel([
FieldPanel('start_date'),
FieldPanel('end_date'),
]),
], heading='Period'),
FieldPanel('location'),
FieldPanel('body'),
StreamFieldPanel('attachments'),
]
promote_panels = Page.promote_panels + [
MultiFieldPanel([
FieldPanel('subscribe'),
], heading='Custom Settings'),
]
settings_panels = TranslatablePage.settings_panels + [
MultiFieldPanel([
FieldPanel('uuid'),
], heading='Meta')
]
parent_page_types = ["home.FolderPage"]
subpage_types = []
On shell, I tried to apply the solution explained on this page but without success.
event = EventPage.objects.get(pk=20)
doc = Document.objects.get(pk=3)
event.attachments = [
('document',
[
StreamValue.StreamChild(
id = None,
block = DocumentChooserBlock(),
value = doc
)
]
)
]
Python give me this error: AttributeError: 'list' object has no attribute 'pk'.
event.attachments = [('document', doc)] should work, I believe. (On the other question you link to, StreamChild was necessary because AccordionRepeaterBlock was a StreamBlock nested in a StreamBlock; that's not the case for your definition.)
To add a document to the existing StreamField content, build a new list and assign that to event.attachments:
new_attachments = [(block.block_type, block.value) for block in blocks]
new_attachments.append(('document', doc))
event.attachments = new_attachments
(Currently you can't append directly to a StreamField value, but this may well be supported in a future Wagtail release...)

MultiFieldPanel width in Wagtail and displayed name

I have the following MultiFieldPanel.
class TeamRooster(Page):
staff = StreamField([
('staff', CardsBlock(Staff(), icon="plus")),
], blank=True)
content_panels = [
MultiFieldPanel(
[ StreamFieldPanel('staff') ],
heading="Staff", classname="col12"
),
three times "Staff" is too much. I looked in the documentation and tried to delete the names but I have a bug.
And how to change the width of MultiFieldPanel? I tried to add classname="full" but it doesn't help me.
As #lb-ben-johnston said I changed content_panels []
Thanks #lb-ben-johnston!

Categories

Resources