Django model update or create object with unique constraint - python

There is a model:
class Proxy(models.Model):
host = models.CharField(max_length=100,)
port = models.CharField(max_length=10,)
login = models.CharField(max_length=100,)
password = models.CharField(max_length=100,)
class Meta:
unique_together = ("host", "port")
I added batch of proxies in admin interface, and one of them is 0.0.0.0:0000, login=123, password=123.
Then I add another batch of proxy, and one of them is the same 0.0.0.0:0000, but with new login=234 and password=234.
Is any possibility to override save method of model to get behaviour like "insert ... on conflict (host, port) do update set login=login, password=password".
Django 2, db - Postgres.

Finally I found answer by myself. If anyone need it here is it:
(1) Deactivate validate_unique on unique fields in model:
def validate_unique(self, exclude=None):
super().validate_unique(exclude='host')
This check is called before save_model() or save() actions. So any other changes will be useless.
(2) Override save method:
def save(self, *args, **kwargs):
proxy = Proxy.objects.get(host=self.host, port=self.port)
if proxy:
self.id = proxy.id
super().save(*args, **kwargs, update_fields=["login", "password"])
else:
super().save(*args, **kwargs)
No update_or_create() or something similar approaches does not work here because they lead to infinite recursion. Just update or save method (even with force_update option) does not work too, because current object have no id yet. So we need to get that id if such object exists and update it or just create new object.

Related

Django - access ManyToManyField right after object was saved

I need to notify users by email, when MyModel object is created. I need to let them know all attributes of this object including ManyToManyFields.
class MyModel(models.Model):
charfield = CharField(...)
manytomany = ManyToManyField('AnotherModel'....)
def to_email(self):
return self.charfield + '\n' + ','.join(self.manytomany.all())
def notify_users(self):
send_mail_to_all_users(message=self.to_email())
The first thing I tried was to override save function:
def save(self, **kwargs):
created = not bool(self.pk)
super(Dopyt, self).save(**kwargs)
if created:
self.notify_users()
Which doesn't work (manytomany appears to be empty QuerySet) probably because transaction haven't been commited yet.
So I tried post_save signal with same result - empty QuerySet.
I can't use m2mchanged signal because:
manytomany can be None
I need to notify users only if object was created, not when it's modified
Do you know how to solve this? Is there some elegant way?

Automate some entries in Django models passing the entry value from same model

This is my models.py code:
from django.db import models
import shortuuid
class website(models.Model):
url = models.URLField(max_length=100)
uid = models.CharField(unique = True, max_length=40,default=str(shortuuid.uuid(name=url)))
def __unicode__(self):
return self.url
In django admin panel the value of uid does not change when I enter a URL.I just want to enter the URL and then want to generate the uid using shortuuid function.I want to set uid as editable=False but before that I want to ensure that the function is woking properly.How to automate the uid value passing url as input?
That's not where you would do it. You can't write something at the class level that depends on an instance attribute of the class: it's simply not possible. And what's more, a default is allocated when the object is instantiated, but you want that to change after the user has changed the value of another attribute, so this isn't a default at all.
Instead you probably want to define this value on save. That's easy to do by simply overriding the save method:
def save(self, *args, **kwargs):
if not self.uid:
self.uid = str(shortuuid.uuid(name=self.user))
return super(website, self).save(*args, **kwargs)

Django redis connection backend or how to implement one

Is there any plugin or 3rd party backend to manage redis connections in Django, so the methods in view.py don't have to explicitly connect to redis for every request?
If not, how would you start implementing one? A new plugin? a new backend? a new django middleware?
Thank you.
I think the emerging standard for non-rel databases is django-nonrel . I don't know if django-nonrel is production ready or if support redis, but they have a guide on writing a custom no-sql backend.
Unfortunately, i don't think that writing support for a redis on standard django is easy as writing a DatabaseBackend. There's a lot in django models mechanics and workflow that simply assumes an ACID database. What about syncdb ? And about Querysets?
However, you may try to write a poor-mans approach using models.Manager and a lot of tweaking on your model. For example:
# helper
def fill_model_instance(instance, values):
""" Fills an model instance with the values from dict values """
attributes = filter(lambda x: not x.startswith('_'), instance.__dict__.keys())
for a in attributes:
try:
setattr(instance, a, values[a.upper()])
del values[a.upper()]
except:
pass
for v in values.keys():
setattr(instance, v, values[v])
return instance
class AuthorManager( models.Manager ):
# You may try to use the default methods.
# But should be freaking hard...
def get_query_set(self):
raise NotImplementedError("Maybe you can write a Non relational Queryset()! ")
def latest(self, *args, **kwargs):
# redis Latest query
pass
def filter(self, *args, **kwargs):
# redis filter query
pass
# Custom methods that you may use, instead of rewriting
# the defaults ones.
def open_connection(self):
# Open a redis connection
pass
def search_author( self, *args, **kwargs ):
self.open_connection()
# Write your query. I don't know how this shiny non-sql works.
# Assumes it returns a dict for every matched author.
authors_list = [{'name': 'Leibniz', 'email': 'iinventedcalculus#gmail.com'},
'name': 'Kurt Godel','email': 'self.consistent.error#gmail.com'}]
return [fill_instance(Author(), author) for author in authors_list]
class Author( models.Model ):
name = models.CharField( max_length = 255 )
email = models.EmailField( max_length = 255 )
def save(self):
raise NotImplementedError("TODO: write a redis save")
def delete(self):
raise NotImplementedError(""TODO: write a delete save")
class Meta:
managed = False
Please not that i've only made an sketch of how you can tweak the django models. I have not
tested and run this code. I first suggest you to investigate django-nonrel.

How to make form validation in Django dynamic?

I'm trying to make a form that handles the checking of a domain: the form should fail based on a variable that was set earlier in another form.
Basically, when a user wants to create a new domain, this form should fail if the entered domain exists.
When a user wants to move a domain, this form should fail if the entered domain doesn't exist.
I've tried making it dynamic overload the initbut couldn't see a way to get my passed variabele to the clean function.
I've read that this dynamic validation can be accomplished using a factory method, but maybe someone can help me on my way with this?
Here's a simplified version of the form so far:
#OrderFormStep1 presents the user with a choice: create or move domain
class OrderFormStep2(forms.Form):
domain = forms.CharField()
extension = forms.CharField()
def clean(self):
cleaned_data = self.cleaned_data
domain = cleaned_data.get("domain")
extension = cleaned_data.get("extension")
if domain and extension:
code = whoislookup(domain+extension);
#Raise error based on result from OrderFormStep1
#raise forms.ValidationError('error, domain already exists')
#raise forms.ValidationError('error, domain does not exist')
return cleaned_data
Overriding the __init__ is the way to go. In that method, you can simply set your value to an instance variable.
def __init__(self, *args, **kwargs):
self.myvalue = kwargs.pop('myvalue')
super(MyForm, self).__init__(*args, **kwargs)
Now self.myvalue is available in any form method.
Do you have a model that stores the domains? If so, you want to use a ModelForm and set unique=True on whichever field stores the actual domain in the model. As of Django 1.2, you can even do any additional validation inside the model, rather than the form.

Django: form values not updating when model updates

I am creating a form that uses MultipleChoiceField. The values for this field are derived from another model. This method works fine, however, I am noticing (on the production server) that when I add a new item to the model in question (NoticeType), the form does not dynamically update. I have to restart the server for the new item to show up on my MultipleChoiceField.
Any changes to the NoticeType model (editing items or creating new ones) do not propagate to the form. After I restart the production server, the updates appear.
Any ideas why this might be ? The relevant portion of the form is below. Thanks.
from django import forms
from django.contrib.auth.models import User
from notification.models import NoticeType
class EditUserProfileForm(forms.Form):
CHOICES = []
for notice in NoticeType.objects.all():
CHOICES.append( (notice.label,notice.display) )
notifications = forms.MultipleChoiceField(
label="Email Notifications",
required=False,
choices=( CHOICES ),
widget=forms.CheckboxSelectMultiple,)
Although mherren is right that you can fix this problem by defining your choices in the __init__ method, there is an easier way: use the ModelMultipleChoiceField which is specifically designed to take a queryset, and updates dynamically.
class EditUserProfileForm(forms.Form):
notifications = forms. ModelMultipleChoiceField(
label="Email Notifications",
required=False,
queryset = NoticeType.objects.all(),
widget=forms.CheckboxSelectMultiple)
My hunch is that the class definition is only being processed once on load rather than for each instantiation. Try adding the CHOICES computation to the init method like so:
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
CHOICES = []
for notice in NoticeType.objects.all():
CHOICES.append( (notice.label, notice.display) )
self.fields['notifications'].choices = CHOICES

Categories

Resources