Wagatail Custom User models not displaying ModelChoiceField - python-3.x

Im using wagtail 4.1 & Django 4.1
I'm trying to create a custom User model which selects from a Snippet I have created.
class User(AbstractUser):
custiommodel= models.ForeignKey(CustomModel, on_delete=models.SET_NULL, null=True, blank=False)
user_type = models.CharField(blank=False, null=False, max_length=20, choices=USER_TYPE_CHOICES)
panels = [
FieldPanel('custommodel'),
FieldPanel('user_type'),
]
class CustomUserCreationForm(UserCreationForm):
user_type = forms.ChoiceField(required=True, choices=USER_TYPE_CHOICES, label=_("User Type"))
custommodel = forms.ModelChoiceField(queryset=CustomModel.objects, required=True,
label=_("Select Organisation"))
In my settings I have
WAGTAIL_USER_EDIT_FORM = 'users.forms.CustomUserEditForm'
This used to previously work on older versions of wagtail. Now the only custom filed i can see from above is 'user_type' which means it's finding the correct file but won't display custom models.
Is this related to this bug which won't allow me to directly register_snipets in the model file but instead in 'wagtail_hooks.py' through view sets?

Related

django-modeltranslate default language duplicate value

My model:
class DoctorSpeciality(BaseModel):
name = models.CharField(max_length=255, unique=True, db_index=True)
class Meta:
db_table = 'doctor_specialities'
When I am trying to translate this model, Django Modeltranslation creates two fields name_de, and name_en. But I also have the name field, name and name_de have the same value. Is it possible not to create a default language column in the database to prevent duplicated values?

In Django, how to create a model that stores proposed changes to another model?

I'm using Python 3.9 and Django 3.2. I have the following model
class Coop(models.Model):
objects = CoopManager()
name = models.CharField(max_length=250, null=False)
types = models.ManyToManyField(CoopType, blank=False)
addresses = models.ManyToManyField(Address, through='CoopAddressTags')
enabled = models.BooleanField(default=True, null=False)
phone = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_phone')
email = models.ForeignKey(ContactMethod, on_delete=models.CASCADE, null=True, related_name='contact_email')
web_site = models.TextField()
description = models.TextField(null=True)
approved = models.BooleanField(default=False, null=True)
We would like to set up a situation where someone could propose a change to a row in the db that would be reviewed before being saved, so I've created this struture
class CoopChange(Coop):
"""
"""
created_at = models.DateTimeField(null=False, default=datetime.now)
The problem is that when I create a migration, the table that is created simply points back to the original model, instead of storing all the fields
Table "public.directory_coopchange"
Column | Type | Modifiers
-------------+--------------------------+-----------
coop_ptr_id | integer | not null
created_at | timestamp with time zone | not null
This is non-ideal because the original table would contain both finalized entries and those suggested for changes. Is there a way to create an entity that stores proposed changes that mirrors the structure of the original entity?
There are a few of ways you could tackle this
Change Coop to an abstract base class:
https://docs.djangoproject.com/en/4.0/topics/db/models/#abstract-base-classes
Then you can inherit two classes from it CoopProposed and CoopApplied and you can work out what logic happens to create each
Just use the one class Coop and add a property called approved defaulted to False and then set it to True when you approve the changes.
This might not be what you want as it will overwrite any previous changes and you might want to keep a history of changes.
Add a property proposed as a JSONField (check the docs if the DB you are using supports it) on the Coop class. This can store a whole dictionary with the keys and values of the proposed changes. When approved, the field can be read and applied to the model's properties in a function or something like that.
class Coop():
objects = CoopManager()
name = models.CharField(max_length=250, null=False)
types = models.ManyToManyField(CoopType, blank=False)
...
proposed = models.JSONField("Proposed Changes", null=True)
def apply_proposed_changes(self):
proposed = self.proposed
self.name = proposed.get('name')
for type in proposed.get('types'):
self.types.add(CoopType.objects.get(name=type))
...
In any case if you're trying to inherit all the properties from Coop you need to understand how Django model inheritance work and all the caveats before you get bitten later down the track:
https://docs.djangoproject.com/en/4.0/topics/db/models/#model-inheritance

How do I add 3 different licenses with 3 different prices in django Models

I have a product and I wanted to add three purchase options that depend on the license you buy.
For example:
class Product(models.Model):
productname = models.CharField(max_length=200)
license = models.????
There should be a multiselector here in order to select all three
licenses when applicable. But how?
discription = models.TextField()
image = models.CharField(max_length=5000, null=True, blank=True)
class License(models.Model):
Here should be some kind of choice field that connects the price to
the choice.... but how???
Help please.
I tried this and it didn't work
class Song(models.Model):
class License(models.IntegerChoices):
BASIC = 35
PREMIUM = 50
PROFESSIONAL = 150
FREE = 0
license = models.IntegerField(choices=License.choices, default='License.FREE')
album = models.ForeignKey(Album, on_delete=models.CASCADE)
artist = models.ForeignKey(Artist, blank=True, on_delete=models.CASCADE)
title = models.CharField(max_length=254)
description = models.TextField()
First of all, you need to keep Product outside of licenses as it will be same for all pricing models.
You can store license info for user in the User model directly or in some custom model that is assigned to the user as OneToOne and contains extra fields for that user.
For pricing, you will just define different prices for each license and product. To make it simpler, you can add ProductPrice as an inline for the Product admin.
class Product(models.Model):
...product related fields here like name and etc.
default_price = models.FloatField("Default price", default=0.0)
def user_price(self, user):
"""Will return ProductPrice model or None if there is no results."""
return self.prices.filter(license=user.license).first()
class License(models.Model):
"""
I would recommend using a custom user model or OneToOne model where you can
assign which license the user have and use `user.license` for that license
value or user.information.license if you use OneToOne model.
"""
...fields related to the License definition only.
class ProductPrice(models.Model):
product = models.ForeignKey(
Product, on_delete=models.CASCADE, related_name="prices"
)
license = models.ForeignKey(
License, on_delete=models.CASCADE, related_name="prices"
)
price = models.FloatField("Price", default=0.0)
...other fields related to license pricing if you need
Thank you everyone that responded. the solution was actually pretty straight forward. It was just like Emin said. I need to make licensing it's own class and a product pricing class with licensing and price. So thanks everything is working

Django dynamic form subclass list

I'm trying to understand how can I define model as a class containing 2 integers and 1 charfield and then make it a part of another model.
Example of data I need
I guess in object oriented programming I should define model class like this:
class Component(models.Model):
pipe_type = models.CharField(max_length=200)
length = models.IntegerField()
amount = models.IntegerField()
And then I don't know how can I use it with django models, it should be something like this:
class Item(models.Model):
name = models.CharField()
components_needed = ? LIST OF Component class ?
Also, since components needed size will wary for objects, it should be possible to extend it's size with button on a page, for example there could be 3 input fields and next to them would be "+" and "-" button to add/remove another set of 3 input fields
I spent entire day looking for solution, but at this point I'm not sure if django can handle this. I'm new to python and django, so there are many things I do not understand.
I will be grateful for any kind of help
the only way now( you canot put multi FK in one cell) is like django itself using with user/groups so you need 3 models.
in django there is group, user and user_group so i suggesting for you:
class Component(models.Model):
pipe_type = models.CharField(max_length=200)
length = models.IntegerField()
amount = models.IntegerField()
class Item(models.Model):
name = models.CharField()
class Item_Component(models.Model):
Component = models.ForeignKey(Component, on_delete=models.CASCADE)
Item = models.ForeignKey(Item, on_delete=models.CASCADE)
so now in third model you can have multiple rows with item and with diffrent component.
open yours db viewer app and see django user_group table.

Multiple document uploads to Wagtail Page

Hi I am new to Wagtail and wondered if there is a simple way of adding multiple downloads to a single page type. I have created a custom page type and would like to be able to add several documents/downloads. I have managed to get one to show, but can find no way of this being extended to add many.
downloads = models.ForeignKey('wagtaildocs.Document', null=True, on_delete=models.SET_NULL)
content_panels = Page.content_panels + [
DocumentChooserPanel('downloads'),
You can do this with a child model associated with your page model, via a ParentalKey and an InlinePanel. The tutorial at http://docs.wagtail.io/en/v1.10.1/getting_started/tutorial.html#images gives an example of this - your setup is very similar, with the only real difference being that you're linking documents to the page rather than images:
class MyPage(Page):
...
content_panels = Page.content_panels + [
InlinePanel('documents', label="Documents")
]
class MyPageDocumentLink(Orderable):
page = ParentalKey(MyPage, related_name='documents')
document = models.ForeignKey(
'wagtaildocs.Document', on_delete=models.CASCADE, related_name='+'
)
panels = [
DocumentChooserPanel('document'),
]

Resources