Updating Schema for Mongoengine - mongoengine

If I have a document like:
class Page(Document):
title = StringField(max_length=200, required=True)
date_modified = DateTimeField(default=datetime.datetime.now)
and I want to update it to:
class Page(Document):
page_title = StringField(max_length=200, required=True)
date_modified = DateTimeField(default=datetime.datetime.now)
what is the best way to handle the database migration in mongoengine? I would imagine you could iterate through the database and pull the objects that have that field and add them back in with the new field then drop all objects that have that field, but it'd be nice if there was an idiomatic way to handle this sort of thing.

I think the easiest way to do it would be by a two-step change of the class.
First add the new field and remove the "required" constraint:
class Page(Document):
title = StringField(max_length=200)
page_title = String(max_length=200)
date_modified = DateTimeField(default=datetime.datetime.now)
Then run the following commands:
for page in Page.objects():
page.page_title = page.title
page.save()
Page.objects.update(unset__title=1) ## Unset the title field of the documents
That will update the documents of your DB without having to drop them (which is useful because they will keep the same id).
Then you make the final modification to your class, as you wanted:
class Page(Document):
page_title = StringField(max_length=200, required=True)
date_modified = DateTimeField(default=datetime.datetime.now)

Related

manyone field with my own default value, Odoo

I have the sale.order model which has the partner_shipping_id.country_id field of the res.country model, what I want is to know how to have a new many2one field (res.country) but that has the sale_order.partner_shipping_id.country_id field loaded by default .
I have tried two ways without being able to get the result:
def _default_country_edit(self):
return self.partner_shipping_id.country_id
country_edit = fields.Many2one('res.country', string="País", default=lambda self: self._default_country_edit())
or:
country_edit = fields.Many2one('res.country', string="País", default=_default_country_edit())
I need something like this:
What I did is in the read method, if you don't have the new field set it and that's it
if not self.country_edit:
self.country_edit = self.partner_shipping_id.country_id
Obviously, in the write method, the sale_order.partner_shipping_id.country_id field must be set with the new one.

How to override field name attribute in django model form?

I have a model form similar to the one below:
class BookSearchForm(ModelForm):
class Meta:
model = Book
fields = ['publisher', 'authors', 'category'
How to override fields name attribute in the above model form?
I tried this, but it did not work:
class BookSearchForm(ModelForm):
class Meta:
model = Book
fields = ['publisher', 'authors', 'category'
widgets = {
'publisher': forms.SelectMultiple(attrs={'name': 'pub'}),
'authors': forms.SelectMultiple(attrs={'name': 'aut'}),
'category': forms.SelectMultiple(attrs={'name': 'cat'}),
}
you don't want to change the name of a field in the forms, django needs that to collect data for that field if you don't provide db_column as the name of the db column. what you can do with the first option, if you want the user to see publisher or some other name, in the models, add a verbose_name and then for the actual name you can declare the field however you want. Your code could look like this
pub = models.WhateverField(verbose_name='what i want you to see')
now when you do {{form.pub.label)}}, 'what i want you to see' is displayed in the html. Of course, don't forget to add the actual input in you template, {{form.pub}}. This way, you don't add anything extra in the form to display a user friendly name. I've posted this as an answer as i ran out of characters for a commment.

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.

Django Form Field Not Setting Value After Submitting

I'm trying to post data from a form that contains incomplete data (I set the missing data in the View class before saving) for the following model. But the form does not get submitted as it is invalid (it's missing the harvest_amount, but I set the value on the webpage before submitting.
class Harvest(models.Model):
harvest_amount = models.IntegerField(validators=[MinValueValidator(limit_value=0)])
harvest_date = models.DateField()
harvest_for_plant = models.ForeignKey(Plant, on_delete=models.CASCADE)
and my form
class HarvestCreationForm(forms.ModelForm):
class Meta:
model = Harvest
fields = [
'harvest_amount'
]
def is_valid(self):
//check if Id in the url contains a valid id for a plant
return True
In this case I forgot to migrate my changes to the model (where a field was deleted). When the form posted the data it would always hit the not null constraint since the deleted field was not being set.

Django Haystack faceting on the model type

I want to facet the results based on the different model_names (classes) returned. Is there an easy way to do this?
Have you tried adding a SearchIndex field with this information? E.g.
class NoteIndex(SearchIndex, indexes.Indexable):
title = CharField(model_attr='title')
facet_model_name = CharField(faceted=True)
def get_model(self):
return Note
def prepare_facet_model_name(self, obj):
return "note"
class MemoIndex(SearchIndex, indexes.Indexable):
title = CharField(model_attr='title')
facet_model_name = CharField(faceted=True)
def get_model(self):
return Memo
def prepare_facet_model_name(self, obj):
return "memo"
And so on, simply returning a different string for each search index. You could also create a mixin and return the name of the model returned by get_model too.
Presuming you've added this field to each of your SearchIndex definitions, just chain the facet method to your results.
results = form.search().facet('facet_model_name')
Now the facet_counts method will return a dictionary with the faceted fields and count of results for each facet value, in this case, the model names.
Note that the field here is labeled verbosely to avoid a possible conflict with model_name, a field added by Haystack. It's not faceted, and I'm not sure if duplicating it will cause a conflict.
If you just want to filter on the model type, you can use the ModelSearchForm
The Docs have a really good walk-through for this.
The minimum you'll need:
is to add faceted=True to the params of your model_names field.
Rebuild your schema and indices.
add .facet('model_names') to whatever SearchQuerySet you're wanting to facet.
More explanation on the question would enable a more complete answer.

Resources